package at.fhhagenberg.hydrac;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Logger;

import at.fhhagenberg.hydrac.backend.codegenerators.AbstractCodeGenerator;
import at.fhhagenberg.hydrac.backend.javacc.generator.ASTGenerator;
import at.fhhagenberg.hydrac.backend.javacc.generator.ParseException;
import at.fhhagenberg.hydrac.backend.javacc.nodes.ASTStart;

/**
 * This Class serves basic Functionality for Cross Compilers. Inheriting Classes have to override abstract Methods to serve specific
 * Compiler Features and Values. All Outputs should be created by the local Field @out.
 * 
 * @author Richard Reiffinger
 */
public abstract class Compiler {
  protected Logger out;

  /**
   * @return Logger which will be used by the Compiler for Output
   */
  public Logger getLogger() {
    return out;
  }

  /**
   * Default Constructor
   */
  public Compiler(Logger logger) {
    out = logger;
  }

  /**
   * Translates a File to the specified Output Format of the Compiler. This Method creates a @ASTStart-Object with a @ASTGenerator and
   * creates an Instance of the @CodeGenerator which will be served by the inheriting Class.
   * 
   * @see at.fhhagenberg.hydrac.backend.codegenerators.AbstractCodeGenerator
   * @see at.fhhagenberg.hydrac.backend.ASTNodes.ASTStart
   * @param fileName
   *          The Input File which contains the Source Code
   */
  public void compile(String fileName) {
    final int extPos = fileName.lastIndexOf(".");
    final String outFileName = fileName.substring(0, extPos > 0 ? extPos : fileName.length()) + "." + getLanguageExt();

    try {
      out.info("Parsing " + fileName + "...");
      final ASTGenerator astGen = new ASTGenerator(new FileInputStream(fileName));
      final ASTStart ast = astGen.Start();
      out.info("Creating " + getLanguageExt() + " Output...");
      final AbstractCodeGenerator cg = getCodeGenerator(outFileName, ast, 2);
      cg.process();
      cg.generateFile();
      out.info("Done.\n");
    } catch (final FileNotFoundException e) {
      out.severe("Unable to find " + fileName);
    } catch (final IOException e) {
      out.severe(e.getMessage());
    } catch (final ParseException e) {
      out.severe(e.getMessage()); 
    } catch (final Exception e) {
      out.severe("Unknown Error: " + e.getMessage());
      e.printStackTrace();
    } // try
  }

  /**
   * Returns a Language specific Code Generator
   * 
   * @param fileName
   *          Filename of the Output File
   * @param ast
   *          Generated ASTStart Object
   * @param nrOfSpaces
   *          Number of Spaces
   * @return A Code Generator which will be used for Compile Processing
   */
  protected abstract AbstractCodeGenerator getCodeGenerator(String fileName, ASTStart ast, int nrOfSpaces) throws IOException;

  /**
   * @return The specific File Extension for a Language, without Extension Separator (e.g. cpp)
   */
  protected abstract String getLanguageExt();
}
